﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace SpiritEngine
{
    // An input device that keeps track of the XBox360 GamePad and GamePadState
    public class CID_XBox360Gamepad : AC_InputDevice<GamePadState>
    {
        // MEMBER VARIABLES
        // ------------------------------------------------------------------------------------------------------------------------

        // The last and current GamePadStates
        GamePadState last;
        GamePadState current;

        // The GamePad buttons that are currently down
        Buttons[] currentButtons;

        // The change in position of the joysticks between the last two frames
        public Vector2 LeftStickDelta = Vector2.Zero;
        public Vector2 RightStickDelta = Vector2.Zero;

        // The change in position of the triggers between the last two frames
        public float LeftTriggerDelta = 0;
        public float RightTriggerDelta = 0;

        // The GamePad's PlayerIndex
        public PlayerIndex PlayerIndex;

        // List of pressed buttons used to setup currentButtons
        List<Buttons> pressed = new List<Buttons>();



        // CONSTRUCTORS
        // ------------------------------------------------------------------------------------------------------------------------

        // Constructor gets the initial GamePadState, and does the first update.
        // It also takes the PlayerIndex of the controller (Player One, Two, Three, or Four)
        public CID_XBox360Gamepad(PlayerIndex PlayerIndex)
            : base()
        {
            this.PlayerIndex = PlayerIndex;

            current = GamePad.GetState(PlayerIndex);
            Update();

        } // end CID_XBox360Gamepad.CID_XBox360Gamepad(PlayerIndex)


        // PRIVATE/PROTECTED METHODS
        // ------------------------------------------------------------------------------------------------------------------------



        // METHODS
        // ------------------------------------------------------------------------------------------------------------------------

        public override void Update()
        {
            // Update the last state
            last = current;

            // Update the current state and clear the list of pressed buttons
            current = GamePad.GetState(PlayerIndex);
            pressed.Clear();

            // Only update if the controller is still connected
            if (IsConnected)
            {
                // If the controller connected this frame, fire the event
                if (!last.IsConnected)
                {
                    if (Connected != null)
                        Connected(this, new EventArgs());
                }


                LeftStickDelta = current.ThumbSticks.Left - last.ThumbSticks.Left;
                RightStickDelta = current.ThumbSticks.Right - last.ThumbSticks.Right;
                LeftTriggerDelta = current.Triggers.Left - last.Triggers.Left;
                RightTriggerDelta = current.Triggers.Right - last.Triggers.Right;

                // For each GamePad button...
                foreach (Buttons Button in Utility.GetEnumValues<Buttons>())
                {
                    // If it is down, add it to the list
                    if (IsButtonDown(Button))
                        pressed.Add(Button);

                    // If it was just pressed, fire the event
                    if (WasButtonPressed(Button))
                    {
                        if (ButtonPressed != null)
                            ButtonPressed(this, new InputDeviceEventArgs<Buttons,GamePadState>(Button, this));
                    }

                    // If it was just released, fire the event
                    if (IsButtonUp(Button))
                    {
                        if (ButtonReleased != null)
                            ButtonReleased(this, new InputDeviceEventArgs<Buttons,GamePadState>(Button, this));
                    }

                    // If it was held, fire the event
                    if (WasButtonHeld(Button))
                    {
                        if (ButtonHeld != null)
                            ButtonHeld(this, new InputDeviceEventArgs<Buttons,GamePadState>(Button, this));
                    }

                } // end foreach


                // Update the currentButtons array from the list of buttons that are down
                currentButtons = pressed.ToArray();

            } // if IsConnected
            else
            {
                // If the controller was just disconnected, fire the event
                if (last.IsConnected)
                {
                    if (Disconnected != null)
                        Disconnected(this, new EventArgs());
                }
            }


        } // end CID_XBox360Gamepad.Update()

        // Whether the specified button is currently down
        public bool IsButtonDown(Buttons Button)
        {
            return current.IsButtonDown(Button);

        } // end CID_XBox360Gamepad.IsButtonDown(Buttons)

        // Whether the specified button is currently up
        public bool IsButtonUp(Buttons Button)
        {
            return current.IsButtonUp(Button);

        } // end CID_XBox360Gamepad.IsButtonUp(Buttons)

        // Whether the specified buton is down for the first time this frame
        public bool WasButtonPressed(Buttons Button)
        {
            if (last.IsButtonUp(Button) && current.IsButtonDown(Button))
                return true;

            return false;

        } // end CID_XBox360Gamepad.WasButtonPressed(Buttons)

        // Whether the specified button is up for the first time this frame
        public bool WasButtonReleased(Buttons Button)
        {
            if (last.IsButtonDown(Button) && current.IsButtonUp(Button))
                return true;

            return false;

        } // end CID_XBox360Gamepad.WasButtonReleased(Buttons)

        // Whether the specified button has been down for more than one frame
        public bool WasButtonHeld(Buttons Button)
        {
            if (last.IsButtonDown(Button) && current.IsButtonDown(Button))
                return true;

            return false;

        } // end CID_XBox360Gamepad.WasButtonHeld(Buttons)


        // DEBUG METHODS
        // ------------------------------------------------------------------------------------------------------------------------

#if (DEBUG)
        // put all debug methods in here...
#endif


        // PROPERTIES
        // ------------------------------------------------------------------------------------------------------------------------

        // State property
        public override GamePadState State
        {
            get
            {
                return current;
            }
        } // end property State

        // PressedButtons property
        public Buttons[] PressedButtons
        {
            get
            {
                return currentButtons;
            }
        } // end property PressedButtons

        // LeftStickPosition property
        // The position of the left joystick
        public Vector2 LeftStickPosition
        {
            get
            {
                return current.ThumbSticks.Left;
            }
        } // end property LeftStickPosition

        // RightStickPosition property
        // The position of the right joystick
        public Vector2 RightStickPosition
        {
            get
            {
                return current.ThumbSticks.Right;
            }
        } // end property RightStickPosition

        // LeftTrigger property
        // The position of the Left Trigger button
        public float LeftTrigger
        {
            get
            {
                return current.Triggers.Left;
            }
        } // end property LeftTrigger

        // RightTrigger property
        // The position of the Right Trigger button
        public float RightTrigger
        {
            get
            {
                return current.Triggers.Right;
            }
        } // end property RightTrigger

        // IsConnected property
        public bool IsConnected
        {
            get
            {
                return current.IsConnected;
            }
        } // end property IsConnected
        


        // EVENTS
        // ------------------------------------------------------------------------------------------------------------------------

        // Events for when a button is pressed, released, or held
        public event InputEventHandler<Buttons, GamePadState> ButtonPressed;
        public event InputEventHandler<Buttons, GamePadState> ButtonReleased;
        public event InputEventHandler<Buttons, GamePadState> ButtonHeld;

        // Events for when the controller is connected and disconnected
        public event EventHandler Connected;
        public event EventHandler Disconnected;



    } // end class CID_XBox360Gamepad

} // end namespace SpiritEngine
